package com.study.apache;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.github.rholder.retry.*;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.junit.jupiter.api.Test;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * @author zhuzi
 * 2024/2/26 13:45
 */
@Slf4j
public class HttpDemo {

    Retryer<RespDTO> retryer = RetryerBuilder.<RespDTO>newBuilder()
            //设置异常重试源|设置结果重试(如果不为true就重试)
            .retryIfExceptionOfType(Exception.class)
            //.retryIfResult(res -> res != null && !res.getLeft())
            .retryIfResult(res -> !res.success)
            //设置等待间隔时间
            .withWaitStrategy(WaitStrategies.fixedWait(3, TimeUnit.SECONDS))
            //设置最大重试次数
            .withStopStrategy(StopStrategies.stopAfterAttempt(3))
            .build();

    @Test
    public void timeout() {
        String url = "http://localhost:8080/abc/timeout";
        RespDTO respDTO = httpPostStatus(url, "", null);
        System.out.println(respDTO);
        try {
            Callable<RespDTO> respDTOCallable = () -> httpPostStatus(url, "", null);
            RespDTO call = retryer.call(respDTOCallable);

        } catch (ExecutionException e) {
        } catch (RetryException e) {
            Attempt<?> attempt = e.getLastFailedAttempt();

            boolean b = attempt.hasException();
            Object result = attempt.getResult();

        }


    }


    private static final String HTTPS = "https";

    public static RespDTO httpPostStatus(String url, String jsonParam, Map<String, String> headerMap) {
        //post请求返回结果
        HttpClient httpClient = HttpClientBuilder.create().build();
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(5000)//设置连接超时时间(ms)|完成TCP三次握手的连接时间上线
                //读取超时,ms，表示从请求的网址获得响应数据的时间间隔
                .setSocketTimeout(4000)
                //值的是从连接池里面获取httpClient连接
                .setConnectionRequestTimeout(5000)
                .build();

        RespDTO respDTO = new RespDTO();
        try {
            HttpPost method = new HttpPost(url);
            if (url.startsWith(HTTPS)) {
                getTrust();
            }
            method.setConfig(requestConfig);
            if (StringUtils.isNotBlank(jsonParam)) {
                //解决中文乱码问题
                StringEntity entity = new StringEntity(jsonParam, ContentType.APPLICATION_JSON);
                entity.setContentEncoding("UTF-8");
                method.setEntity(entity);
                method.setHeader("Content-Type", " application/json;charset=utf-8");
                if (MapUtil.isNotEmpty(headerMap)) {
                    headerMap.forEach((k, v) -> {
                        method.setHeader(k, v);
                    });
                }
            }
            HttpResponse result = httpClient.execute(method);
            url = URLDecoder.decode(url, StandardCharsets.UTF_8.name());
            /**请求发送成功，并得到响应**/
            respDTO.setStatusCode(result.getStatusLine().getStatusCode());
            if (result.getStatusLine().getStatusCode() == 200) {
                respDTO.setSuccess(true).setErrMsg(null);
                try {
                    /**读取服务器返回过来的json字符串数据**/
                    String resp = EntityUtils.toString(result.getEntity());
                    respDTO.setResp(resp);
                    log.info("发送[{}]得到的响应是[{}]", url, resp);
                } catch (Exception e) {
                    log.error("post请求提交失败{}:" + url, e);
                }
            }
        } catch (IOException e) {
            respDTO.setErrMsg(e.getMessage());
            System.out.println(StrUtil.format("错我异常{}", e.getClass()));
            log.error("post请求提交失败1:" + url, e);
        }
        return respDTO;
    }

    private static void getTrust() {
        try {
            HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
            SSLContext context = SSLContext.getInstance("TLS");
            context.init(null, new X509TrustManager[]{new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                }

                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[0];
                }
            }}, new SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Data
    @Accessors(chain = true)
    public static class RespDTO {
        private int statusCode;
        private String resp;
        private boolean success;

        private String errMsg;

        public RespDTO setStatusCode(int statusCode) {
            this.statusCode = statusCode;
            return this;
        }
    }
}
